﻿using System;
using System.Collections.Generic;
using System.Text;

namespace daStaticAnalyser.Analysers
{
    using daSyntaxAnalyser.SyntaxTree;

    public class ControlGraph
    {
        EG root;
        public List<EG> Elements;
        public List<ELink> Links;

        public ControlGraph()
        {
            Elements = new List<EG>();
            Links = new List<ELink>();
            root = new EGLink("Start");
            root.Last = null;
            Elements.Add(root);
        }

        public void Build(ISyntaxTreeElement elt)
        {
            GetGraph(root, elt, null);
        }

        EG GetGraph(EG LastNode, ISyntaxTreeElement elt, EG owner)
        {
            EG ret = LastNode;
            if (elt is StatementsElement)
            {
                EG PrevNode = LastNode;
                foreach (var elt2 in elt)
                {
                    EG CurNode = GetGraph(PrevNode, elt2, owner);
                    PrevNode = CurNode;
                    ret = CurNode;
                }
            }
            else if ((elt is AssignmentElement) ||
                     (elt is VariableStatementElement) ||
                     (elt is GotoStatementElement) ||
                     (elt is ExceptStatementElement))
            {
                EG CurNode = new EG(elt.ToString());
                CurNode.Last = owner;
                Elements.Add(CurNode);
                LastNode.Next.Add(CurNode);
                Links.Add(new ELink(LastNode, CurNode));
                ret = CurNode;
            }
            else if (elt is TestStatementElement)
            {
                var TestSE = elt as TestStatementElement;
                ret = new EGLink("Test exit");
                Elements.Add(ret);
                EG beg = new EGLink("Test enter");
                beg.Last = owner;
                ret.Last = owner;
                Elements.Add(beg);
                LastNode.Next.Add(beg);
                Links.Add(new ELink(LastNode, beg));
                EG ThenE = GetGraph(beg, TestSE.IfTrue, beg);
                ThenE.Next.Add(ret);
                Links.Add(new ELink(ThenE, ret));
                if (TestSE.IfFalse != null)
                {
                    EG ElseE = GetGraph(beg, TestSE.IfFalse, beg);
                    ElseE.Next.Add(ret);
                    Links.Add(new ELink(ElseE, ret));
                }
                else
                {
                    beg.Next.Add(ret);
                    Links.Add(new ELink(beg, ret));
                }
            }
            else if (elt is CaseStatementElement)
            {
                var CaseSE = elt as CaseStatementElement;
                ret = new EGLink("Case exit");
                Elements.Add(ret);
                EG beg = new EGLink("Case enter");
                beg.Last = owner;
                ret.Last = beg;
                Elements.Add(beg);
                LastNode.Next.Add(beg);
                Links.Add(new ELink(LastNode, beg));
                foreach (var CaseBlock in CaseSE.Cases)
                {
                    EG CaseBlockE = GetGraph(beg, CaseBlock, beg);
                    CaseBlockE.Next.Add(ret);
                    Links.Add(new ELink(CaseBlockE, ret));
                }
            }
            else if (elt is WhileStatementElement)
            {
                var WhileSE = elt as WhileStatementElement;
                ret = new EGLink("While Point");
                ret.Last = owner;
                Elements.Add(ret);
                LastNode.Next.Add(ret);
                Links.Add(new ELink(LastNode, ret));
                EG temp = GetGraph(ret, WhileSE.Statement, ret);
                temp.Next.Add(ret);
                Links.Add(new ELink(temp, ret));
            }
            else if (elt is RepeatStatementElement)
            {
                var RepeatSE = elt as RepeatStatementElement;
                ret = new EGLink("Repeat Point");
                ret.Last = owner;
                Elements.Add(ret);
                EG temp = GetGraph(LastNode, RepeatSE.Statements[0], ret);
                temp.Next.Add(ret);
                Links.Add(new ELink(temp, ret));
                ret.Next.Add(temp);
                Links.Add(new ELink(ret, temp));
            }
            else if (elt is ForStatementElement)
            {
                var ForSE = elt as ForStatementElement;
                ret = new EGLink("For Point");
                ret.Last = owner;
                Elements.Add(ret);
                EG start = new EG("For start");
                ret.Last = owner;
                Elements.Add(start);
                LastNode.Next.Add(start);
                Links.Add(new ELink(LastNode, start));
                start.Next.Add(ret);
                Links.Add(new ELink(start, ret));
                EG temp = GetGraph(ret, ForSE.Statement, ret);
                EG iter = new EG("For iteration");
                iter.Last = ret;
                Elements.Add(iter);
                temp.Next.Add(iter);
                Links.Add(new ELink(temp, iter));
                iter.Next.Add(ret);
                Links.Add(new ELink(iter, ret));
            }
            else if ((elt is CompoundStatementElement) ||
                     (elt is CompoundStatementElement) ||
                     (elt is CaseBlockStatementElement))
            {
                foreach (ISyntaxTreeElement element in elt)
                    ret = GetGraph(ret, element, owner);
            }
            return ret;
        }
    }

    public class EG//Класс - элемент управляющего графа
    {
        public bool Visit;
        public List<EG> Next;
        public EG Last;
        public String Text;

        public EG(String Text1)
        {
            Visit = false;
            Next = new List<EG>();
            Text = Text1;
        }
    }

    public class EGLink : EG
    {
        public EGLink(String Text1) : base(Text1) { }
    }

    public class ELink
    {
        EG One;
        EG Two;
        public ELink(EG One1, EG Two1)
        {
            One1 = One;
            Two1 = Two;
        }
    }
}
